package com.flyone.fuxiao.service.impl;

import cn.hutool.http.HttpRequest;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.flyone.fuxiao.common.ErrorCode;
import com.flyone.fuxiao.common.Result;
import com.flyone.fuxiao.constant.CommonConstant;
import com.flyone.fuxiao.constant.ModelConstant;
import com.flyone.fuxiao.exception.BusinessException;
import com.flyone.fuxiao.mapper.PicturePostMapper;
import com.flyone.fuxiao.model.dto.file.GenerateImgRequest;
import com.flyone.fuxiao.model.dto.img2img.Img2imgRequest;
import com.flyone.fuxiao.model.dto.txt2img.PicturePostQueryRequest;
import com.flyone.fuxiao.model.dto.txt2img.Txt2ImgRequest;
import com.flyone.fuxiao.model.entity.PicturePost;
import com.flyone.fuxiao.model.entity.PostHistory;
import com.flyone.fuxiao.model.entity.User;
import com.flyone.fuxiao.model.entity.sd.Model;
import com.flyone.fuxiao.model.entity.sd.Vae;
import com.flyone.fuxiao.model.res.StartFireResponse;
import com.flyone.fuxiao.model.res.TranslationResponse;
import com.flyone.fuxiao.model.res.ImgResponse;
import com.flyone.fuxiao.model.vo.PostVO;
import com.flyone.fuxiao.model.vo.StarFireResponseVO;
import com.flyone.fuxiao.model.vo.ImgResponseVO;
import com.flyone.fuxiao.service.PicturePostService;
import com.flyone.fuxiao.service.PostHistoryService;
import com.flyone.fuxiao.utils.ImageUtils;
import com.flyone.fuxiao.utils.NetUtils;
import com.flyone.fuxiao.utils.SqlUtils;
import com.google.gson.Gson;
import lombok.SneakyThrows;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author luoyifei
 */
@Service
public class PicturePostServiceImpl extends ServiceImpl<PicturePostMapper, PicturePost>
        implements PicturePostService {

    static Gson gson = new Gson();
    @Value("${fuxiao.sd.txt2img.url}")
    String sd_url;
    @Resource
    private ImageUtils imageUtils;
    @Value("${fuxiao.starfire.hostUrl}")
    private String hostUrl;
    @Value("${fuxiao.starfire.appid}")
    private String appid;
    @Value("${fuxiao.starfire.apiKey}")
    private String apiKey;
    @Value("${fuxiao.starfire.apiSecret}")
    private String apiSecret;
    private static final String TXT_2_IMG_PATH = "/sdapi/v1/txt2img";
    private static final String IMG_2_IMG_PATH = "/sdapi/v1/img2img";
    @Resource
    private PostHistoryService postHistoryService;

    private static String getPrompt(String prompt) {
        String translations = NetUtils.getTranslations(prompt);
        TranslationResponse translationResponse = gson.fromJson(translations, TranslationResponse.class);
        return translationResponse.getData().getTranslate_result();
    }

    @SneakyThrows
    @Override
    public StarFireResponseVO generationImg(GenerateImgRequest generateImgRequest, String token, User loginUser) {
        String authUrl = imageUtils.getAuthUrl(hostUrl, apiKey, apiSecret);
        String prompt = generateImgRequest.getPrompt();
        // 请求参数
        String json = "{\n" +
                "  \"header\": {\n" +
                "    \"app_id\": \"" + appid + "\",\n" +
                "    \"uid\": \"" + UUID.randomUUID().toString().substring(0, 15) + "\"\n" +
                "  },\n" +
                "  \"parameter\": {\n" +
                "    \"chat\": {\n" +
                "      \"domain\": \"s291394db\",\n" +
                "      \"temperature\": 0.5,\n" +
                "      \"max_tokens\": 4096,\n" +
                "      \"width\": " + generateImgRequest.getWidth() + ",\n" +
                "      \"height\": " + generateImgRequest.getHeight() + "\n" +
                "    }\n" +
                "  },\n" +
                "  \"payload\": {\n" +
                "    \"message\": {\n" +
                "      \"text\": [\n" +
                "        {\n" +
                "          \"role\": \"user\",\n" +
                "          \"content\": \"" + prompt + "\"\n" +
                "        }\n" +
                "      ]\n" +
                "    }\n" +
                "  }\n" +
                "}";
        // 发起Post请求
        String response = imageUtils.doPostJson(authUrl, null, json);
        StartFireResponse startFireResponse = new Gson().fromJson(response, StartFireResponse.class);

        // 特殊异常捕获：如(1) 涉及国家安全的信息；(2) 涉及政治与宗教类的信息；(3) 涉及暴力与恐怖主义的信息；
        // (4) 涉及黄赌毒类的信息；(5) 涉及不文明的信息。并通过Result类返回给前端页面（字符串格式），同时控制台打印
        if (startFireResponse != null && startFireResponse.getHeader() != null &&
                (startFireResponse.getHeader().getCode() == 10021)) {
                String errorMessage = startFireResponse.getHeader().getMessage();
                log.error(errorMessage);
                return new StarFireResponseVO(String.valueOf(Result.error(errorMessage)));

        }

        // 获取图片
        String imgUrl = imageUtils.getImage(startFireResponse);
        if ("上传失败".equals(imgUrl)) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "生成图片失败");
        }
        savePicturePost(prompt, ModelConstant.STARFIRE, loginUser, imgUrl);
        if("".equals(token)) {
            token = NetUtils.generateUUID();
        }
        savePostHistory(prompt, token, imgUrl, loginUser);
        StarFireResponseVO starFireResponseVO = new StarFireResponseVO();
        starFireResponseVO.setToken(token);
        starFireResponseVO.setImages(new ArrayList<>(Collections.singletonList(imgUrl)));

        return starFireResponseVO;
    }

    @Override
    public Wrapper<PicturePost> getQueryWrapper(PicturePostQueryRequest postQueryRequest) {
        QueryWrapper<PicturePost> queryWrapper = new QueryWrapper<>();
        String sortOrder = postQueryRequest.getSortOrder();
        String sortField = postQueryRequest.getSortField();
        String searchText = postQueryRequest.getSearchText();
        List<String> tagList = postQueryRequest.getTags();
        // 如果标题不为空，则添加标题的查询条件
        if (StringUtils.isNotBlank(searchText)) {
            queryWrapper.like("userDescription", searchText);
        }
        // 如果内容不为空，则添加内容的查询条件
        if (StringUtils.isNotBlank(postQueryRequest.getUserDescription())) {
            queryWrapper.like("userDescription", postQueryRequest.getUserDescription());
        }

        // 如果modelType不为空，则添加modelType的查询条件
        if (StringUtils.isNotBlank(postQueryRequest.getModelType())){
            queryWrapper.like("modelType",postQueryRequest.getModelType());
        }
        // 如果modelName不为空，则添加modelName的查询条件
        if (StringUtils.isNotBlank(postQueryRequest.getModelName())){
            queryWrapper.like("modelName",postQueryRequest.getModelName());
        }

        // 如果标签列表不为空，则添加标签的查询条件
        if (postQueryRequest.getTags() != null && !postQueryRequest.getTags().isEmpty()) {
            queryWrapper.in("tags", postQueryRequest.getTags());
        }

        // 如果用户ID不为空，则添加ID的查询条件
        if (ObjectUtils.isNotEmpty(postQueryRequest.getUserId())) {
            queryWrapper.eq("userId", postQueryRequest.getUserId());
        }

        // 如果至少有一个标签不为空，则添加至少有一个标签的查询条件
        if (CollectionUtils.isNotEmpty(tagList)) {
            for (String tag : tagList) {
                queryWrapper.like("tags", "\"" + tag + "\"");
            }
        }
//        if (postQueryRequest.getOrTags() != null && !postQueryRequest.getOrTags().isEmpty()) {
//            queryWrapper.or().in("tags", postQueryRequest.getOrTags());
//        }
        queryWrapper.orderBy(SqlUtils.validSortField(sortField), sortOrder.equals(CommonConstant.SORT_ORDER_ASC),
                sortField);
        return queryWrapper;
    }

    // TODO
    @Override
    public Page<PostVO> getPostVOPage(Page<PicturePost> postPage, HttpServletRequest request) {
        // 使用getQueryWrapper方法获取查询条件
        Wrapper<PicturePost> queryWrapper = getQueryWrapper(new PicturePostQueryRequest());

        // 使用查询条件执行分页查询
        Page<PicturePost> resultPage = baseMapper.selectPage(postPage, queryWrapper);

        // 将查询结果转换为PostVO对象
        List<PostVO> postVOList = resultPage.getRecords().stream()
                .map(picturePost -> {
                    PostVO postVO = new PostVO();
                    BeanUtils.copyProperties(picturePost, postVO);
                    return postVO;
                })
                .collect(Collectors.toList());

        // 创建一个新的Page对象，其记录类型为PostVO
        Page<PostVO> postVOPage = new Page<>(resultPage.getCurrent(), resultPage.getSize(), resultPage.getTotal());

        // 将PostVO对象的列表设置为新Page对象的记录
        postVOPage.setRecords(postVOList);

        // 返回包含PostVO对象的Page对象
        return postVOPage;
    }

    @Override
    public ImgResponseVO txt2img(Txt2ImgRequest txt2ImgRequest, String token, User loginUser) {
        // 获取中文提示词
        String zhPrompt = txt2ImgRequest.getPrompt();
        // 将中文转为英文提示词
        String prompt = getPrompt(zhPrompt);
        // 替换中文逗号
        prompt = prompt.replace("，", ",");
        List<String> urlList = new ArrayList<>();
        // 拼接默认提示词
        prompt = prompt.endsWith(",") ? prompt + ModelConstant.BASE_PROMPT
                : prompt + "," + ModelConstant.BASE_PROMPT;
        txt2ImgRequest.setPrompt(prompt);
        // 拼接默认反向提示词
        String negative_prompt = txt2ImgRequest.getNegative_prompt();
        if (txt2ImgRequest.getNegative_prompt() == null) {
            negative_prompt += ModelConstant.BASE_NEGATIVE_PROMPT;
        } else {
            negative_prompt += "," + ModelConstant.BASE_PROMPT;
        }
        txt2ImgRequest.setNegative_prompt(negative_prompt);
        // JSON 格式化
        String json = gson.toJson(txt2ImgRequest);
        String body = HttpRequest.post(sd_url + TXT_2_IMG_PATH).
                header("Content-Type", "application/json").
                body(json).
                execute().body();
        ImgResponse imgResponse = gson.fromJson(body, ImgResponse.class);
        List<String> images = imgResponse.getImages();
        for (String image : images) {
            String url = imageUtils.getImageBytes(image, "txt2img-images");
            urlList.add(url);
        }
        savePicturePost(zhPrompt, prompt,
                txt2ImgRequest.getOverride_settings().getSd_model_checkpoint()
                , ModelConstant.SD, loginUser, urlList);
        if("".equals(token)) {
            token = NetUtils.generateUUID();
        }
        savePostHistory(zhPrompt, token, urlList.toString(), loginUser);
        ImgResponseVO imgResponseVO = new ImgResponseVO();
        BeanUtils.copyProperties(imgResponse, imgResponseVO);
        imgResponseVO.setImages(urlList);
        imgResponseVO.setToken(token);
        return imgResponseVO;
    }


//    @Override
//    public String img2img(Img2imgRequest img2imgRequest, String type, User loginUser) {
//        String zhPrompt = null, prompt = null;
//        String url = "";
//        if (img2imgRequest.getPrompt() == null || img2imgRequest.getPrompt().isEmpty()) {
//            img2imgRequest.setPrompt(ModelConstant.BASE_PROMPT);
//        } else {
//            // 获取中文提示词
//            zhPrompt = img2imgRequest.getPrompt();
//            // 将中文转为英文提示词
//            prompt = getPrompt(zhPrompt);
//            // 替换中文逗号
//            prompt = prompt.replace("，", ",");
//            // 拼接默认提示词
//            prompt = prompt.endsWith(",") ? prompt + ModelConstant.BASE_PROMPT
//                    : prompt + "," + ModelConstant.BASE_PROMPT;
//        }
//        // 拼接默认反向提示词
//        String negative_prompt = img2imgRequest.getNegative_prompt();
//        if (img2imgRequest.getNegative_prompt() == null || img2imgRequest.getNegative_prompt().isEmpty()) {
//            negative_prompt += ModelConstant.BASE_NEGATIVE_PROMPT;
//        } else {
//            negative_prompt += "," + ModelConstant.BASE_PROMPT;
//        }
//        img2imgRequest.setNegative_prompt(negative_prompt);
//        // JSON 格式化
//        String json = gson.toJson(img2imgRequest);
//        String body = HttpRequest.post(sd_url + IMG_2_IMG_PATH).
//                header("Content-Type", "application/json").
//                body(json).
//                execute().body();
//        ImgResponse imgResponse = gson.fromJson(body, ImgResponse.class);
//        List<String> images = imgResponse.getImages();
//        for (String image : images) {
//            url = imageUtils.getImageBytes(image, "img2img-images");
//        }
//        return url;
//    }

    @Override
    public String img2img(Img2imgRequest img2imgRequest, String type, User loginUser) {
        String zhPrompt = null, prompt = null;
        String url = "";

        if ("handDraw".equals(type)) {
            // 手绘生图逻辑
            if (img2imgRequest.getPrompt() == null || img2imgRequest.getPrompt().isEmpty()) {
                img2imgRequest.setPrompt(ModelConstant.BASE_PROMPT);
            } else {
                // 获取中文提示词
                zhPrompt = img2imgRequest.getPrompt();
                // 将中文转为英文提示词
                prompt = getPrompt(zhPrompt);
                // 替换中文逗号
                prompt = prompt.replace("，", ",");
                // 拼接默认提示词
                prompt = prompt.endsWith(",") ? prompt + ModelConstant.BASE_PROMPT
                        : prompt + "," + ModelConstant.BASE_PROMPT;
            }
            // 拼接默认反向提示词
            String negative_prompt = img2imgRequest.getNegative_prompt();
            if (img2imgRequest.getNegative_prompt() == null || img2imgRequest.getNegative_prompt().isEmpty()) {
                negative_prompt += ModelConstant.BASE_NEGATIVE_PROMPT;
            } else {
                negative_prompt += "," + ModelConstant.BASE_NEGATIVE_PROMPT;
            }
            img2imgRequest.setNegative_prompt(negative_prompt);
        } else {
            // 图生图逻辑
            if (img2imgRequest.getPrompt() == null || img2imgRequest.getPrompt().isEmpty()) {
                img2imgRequest.setPrompt(ModelConstant.BASE_PROMPT);
            } else {
                // 获取中文提示词
                zhPrompt = img2imgRequest.getPrompt();
                // 将中文转为英文提示词
                prompt = getPrompt(zhPrompt);
                // 替换中文逗号
                prompt = prompt.replace("，", ",");
                // 拼接默认提示词
                prompt = prompt.endsWith(",") ? prompt + ModelConstant.BASE_PROMPT
                        : prompt + "," + ModelConstant.BASE_PROMPT;
            }
            // 拼接默认反向提示词
            String negative_prompt = img2imgRequest.getNegative_prompt();
            if (img2imgRequest.getNegative_prompt() == null || img2imgRequest.getNegative_prompt().isEmpty()) {
                negative_prompt += ModelConstant.BASE_NEGATIVE_PROMPT;
            } else {
                negative_prompt += "," + ModelConstant.BASE_NEGATIVE_PROMPT;
            }
            img2imgRequest.setNegative_prompt(negative_prompt);
        }

        String json = gson.toJson(img2imgRequest);
        String body = HttpRequest.post(sd_url + IMG_2_IMG_PATH)
                .header("Content-Type", "application/json")
                .body(json)
                .execute()
                .body();
        ImgResponse imgResponse = gson.fromJson(body, ImgResponse.class);
        List<String> images = imgResponse.getImages();
        for (String image : images) {
            url = imageUtils.getImageBytes(image, "img2img-images");
        }
        return url;
    }

    @Override
    public Model[] getSdModels() {
        String apiPath = "/sdapi/v1/sd-models";
        String body = HttpRequest.get(sd_url + apiPath).
                execute().body();

        return gson.fromJson(body, Model[].class);
    }

    @Override
    public Vae[] getSdVae() {
        String apiPath = "/sdapi/v1/sd-vae";
        String body = HttpRequest.get(sd_url + apiPath).
                execute().body();
        return gson.fromJson(body, Vae[].class);
    }

    private void savePicturePost(String prompt, String modelName, User loginUser, String imgUrl) {
        PicturePost picturePost = new PicturePost();
        picturePost.setUserDescription(prompt);
        picturePost.setPrompt(prompt);
        picturePost.setContentUrl(imgUrl);
        picturePost.setModelType(modelName);
        picturePost.setTags(prompt);
        picturePost.setUserId(loginUser.getId());
        picturePost.setPrompt(prompt);
        picturePost.setCreateBy(loginUser.getUserName());
        save(picturePost);
    }

    private void savePicturePost(String zhPrompt, String prompt,
                                String modelName, String modelType, User loginUser, List<String> imgUrl) {
        PicturePost picturePost = new PicturePost();
        picturePost.setUserDescription(zhPrompt);
        picturePost.setPrompt(prompt);
        picturePost.setContentUrl(imgUrl.toString());
        picturePost.setModelType(modelType);
        picturePost.setModelName(modelName);
        picturePost.setTags(prompt);
        picturePost.setUserId(loginUser.getId());
        picturePost.setCreateBy(loginUser.getUserName());
        save(picturePost);
    }

    private void savePostHistory(String zhPrompt, String token, String urlList, User loginUser) {
        PostHistory postHistory = new PostHistory();
        postHistory.setPrompt(zhPrompt);
        postHistory.setToken(token);
        postHistory.setContentUrl(Collections.singletonList(urlList).toString());
        postHistory.setUserId(loginUser.getId());
        postHistoryService.save(postHistory);
    }


}




